package com.epam.dao.impl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import org.apache.log4j.Logger;

import com.epam.dao.intf.IHotelDAO;
import com.epam.database.ConnectionPool;
import com.epam.entity.AbstractEntity;
import com.epam.entity.Hotel;
import com.epam.entity.Hotel.Feeding;

public class HotelDAO implements IHotelDAO {

	
	private static final Logger LOG = Logger.getLogger(HotelDAO.class);
	private static final String INSERT_HOTEL = "INSERT INTO HOTELS (name, stars, tv, conditioning, feeding) values (?,?,?,?,?)";
	private static final String FIND_HOTEL_BY_NAME = "SELECT * FROM hotels WHERE name = ?";
	private static final String FIND_HOTEL_BY_ID = "SELECT * FROM hotels WHERE hotel_id = ?";
	private static final String FIND_ALL_HOTELS = "SELECT * FROM hotels";
	
	public void insert(AbstractEntity entity)  {
		try {
			Connection connection = ConnectionPool.INSTANCE.takeConnection();
			PreparedStatement st = connection.prepareStatement(INSERT_HOTEL);
			
			Hotel hotel = (Hotel) entity;
			
			st.setString(1, hotel.getName());
			st.setInt(2, hotel.getStars());
			st.setBoolean(3, hotel.isTv());
			st.setBoolean(4, hotel.isConditioning());
			st.setString(5, hotel.getFeeding().toString());

			st.execute();
			LOG.info("Hotel inserted " + hotel.toString());
			ConnectionPool.INSTANCE.retreiveConnection(connection);
		} catch (SQLException e) {
			LOG.error(e);
		}
	}

	public Hotel findByName(String name) {
		try {
			
			Connection connection = ConnectionPool.INSTANCE.takeConnection();
			PreparedStatement st = connection
					.prepareStatement(FIND_HOTEL_BY_NAME);
			st.setString(1, name);
			ResultSet rs = st.executeQuery();

			if (rs.isBeforeFirst()) {
				rs.next();

				Hotel hotel = construct(rs);
				
				ConnectionPool.INSTANCE.retreiveConnection(connection);
				return hotel;
			}
		} catch (SQLException e) {
			LOG.error(e);
		}
		return null;

	}

	public Hotel findByID(int id) {
		try {
			Connection connection = ConnectionPool.INSTANCE.takeConnection();
			PreparedStatement st = connection
					.prepareStatement(FIND_HOTEL_BY_ID);
			st.setInt(1, id);
			ResultSet rs = st.executeQuery();

			if (rs.isBeforeFirst()) {
				rs.next();

				Hotel hotel = construct(rs);

				ConnectionPool.INSTANCE.retreiveConnection(connection);
				return hotel;
			}
		} catch (SQLException e) {
			LOG.error(e);
		}
		return null;
	}

	public List<AbstractEntity> findAll() {
		List<AbstractEntity> hotels = null;
		try {
			hotels = new LinkedList<AbstractEntity>();
			Connection connection = ConnectionPool.INSTANCE.takeConnection();
			PreparedStatement st = connection.prepareStatement(FIND_ALL_HOTELS);
						
			ResultSet rs = st.executeQuery();
			while (rs.next()) {
				Hotel hotel = construct(rs);
				hotels.add(hotel);
			}
			ConnectionPool.INSTANCE.retreiveConnection(connection);
		} catch (SQLException e) {
			LOG.error(e);
		}
		return hotels;
	}
	
	private Hotel construct(ResultSet rs){
		
		try {
		int hotelId = Integer.parseInt(rs.getString("hotel_id"));
		String hotelName = rs.getString("name");
		int stars = rs.getInt("stars");
		boolean tv = rs.getBoolean("tv");
		boolean conditioning = rs.getBoolean("conditioning");
		Feeding feeding = Enum.valueOf(Hotel.Feeding.class,
				rs.getString("feeding"));
		
		Hotel hotel = new Hotel.HotelBuilder().name(hotelName)
				.stars(stars).tv(tv).conditioning(conditioning)
				.feeding(feeding).id(hotelId).build();
		
		return hotel;
		} catch (SQLException e) {
			LOG.error(e);
		}
		return null;
	}
	
	@Override
	public List<AbstractEntity> findAllPaginated(int offset,
			int numberOfRecords) {
		Connection connection = ConnectionPool.INSTANCE.takeConnection();
		List<AbstractEntity> hotels = new ArrayList<AbstractEntity>();

		try {
			PreparedStatement st = connection.prepareStatement(
					"SELECT * FROM hotels OFFSET ? LIMIT ?",
					ResultSet.TYPE_SCROLL_INSENSITIVE,
					ResultSet.CONCUR_UPDATABLE);
			st.setInt(1, offset);
			st.setInt(2, numberOfRecords);
			ResultSet rs = st.executeQuery();

			while (rs.next()) {
				Hotel hotel = construct(rs);
				hotels.add(hotel);
			}

		} catch (SQLException e) {
			LOG.error(e);
		}
		ConnectionPool.INSTANCE.retreiveConnection(connection);
		System.out.println(hotels.toString());
		return hotels;

	}
}